// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000-2002.  All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License/free.pdf

#include "MgcVector2.h"
using namespace Mgc;

const Vector2 Vector2::ZERO(0.0f,0.0f);
const Vector2 Vector2::UNIT_X(1.0f,0.0f);
const Vector2 Vector2::UNIT_Y(0.0f,1.0f);
Real Vector2::FUZZ = 0.0f;

//----------------------------------------------------------------------------
Vector2::Vector2 (Real fX, Real fY)
{
    x = fX;
    y = fY;
}
//----------------------------------------------------------------------------
Vector2::Vector2 (Real afCoordinate[2])
{
    x = afCoordinate[0];
    y = afCoordinate[1];
}
//----------------------------------------------------------------------------
Vector2::Vector2 (const Vector2& rkVector)
{
    x = rkVector.x;
    y = rkVector.y;
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator= (const Vector2& rkVector)
{
    x = rkVector.x;
    y = rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
bool Vector2::operator== (const Vector2& rkVector) const
{
    if ( FUZZ == 0.0f )
        return x == rkVector.x && y == rkVector.y;
    else
        return Math::FAbs(x-rkVector.x) <= FUZZ 
            && Math::FAbs(y-rkVector.y) <= FUZZ;
}
//----------------------------------------------------------------------------
bool Vector2::operator!= (const Vector2& rkVector) const
{
    if ( FUZZ == 0.0f )
        return x != rkVector.x || y != rkVector.y;
    else
        return Math::FAbs(x-rkVector.x) > FUZZ
             || Math::FAbs(y-rkVector.y) > FUZZ;
}
//----------------------------------------------------------------------------
bool Vector2::operator< (const Vector2& rkVector) const
{
    Real fXTmp = rkVector.x, fYTmp = rkVector.y;
    if ( FUZZ > 0.0f )
    {
        if ( Math::FAbs(x - fXTmp) <= FUZZ )
            fXTmp = x;
        if ( Math::FAbs(y - fYTmp) <= FUZZ )
            fYTmp = y;
    }

    // compare y values
    unsigned int uiTest0 = *(unsigned int*)&y;
    unsigned int uiTest1 = *(unsigned int*)&fYTmp;
    if ( uiTest0 < uiTest1 )
        return true;
    if ( uiTest0 > uiTest1 )
        return false;

    // compare x values
    uiTest0 = *(unsigned int*)&x;
    uiTest1 = *(unsigned int*)&fXTmp;
    return uiTest0 < uiTest1;
}
//----------------------------------------------------------------------------
bool Vector2::operator<= (const Vector2& rkVector) const
{
    Real fXTmp = rkVector.x, fYTmp = rkVector.y;
    if ( FUZZ > 0.0f )
    {
        if ( Math::FAbs(x - fXTmp) <= FUZZ )
            fXTmp = x;
        if ( Math::FAbs(y - fYTmp) <= FUZZ )
            fYTmp = y;
    }

    // compare y values
    unsigned int uiTest0 = *(unsigned int*)&y;
    unsigned int uiTest1 = *(unsigned int*)&fYTmp;
    if ( uiTest0 < uiTest1 )
        return true;
    if ( uiTest0 > uiTest1 )
        return false;

    // compare x values
    uiTest0 = *(unsigned int*)&x;
    uiTest1 = *(unsigned int*)&fXTmp;
    return uiTest0 <= uiTest1;
}
//----------------------------------------------------------------------------
bool Vector2::operator> (const Vector2& rkVector) const
{
    Real fXTmp = rkVector.x, fYTmp = rkVector.y;
    if ( FUZZ > 0.0f )
    {
        if ( Math::FAbs(x - fXTmp) <= FUZZ )
            fXTmp = x;
        if ( Math::FAbs(y - fYTmp) <= FUZZ )
            fYTmp = y;
    }

    // compare y values
    unsigned int uiTest0 = *(unsigned int*)&y;
    unsigned int uiTest1 = *(unsigned int*)&fYTmp;
    if ( uiTest0 > uiTest1 )
        return true;
    if ( uiTest0 < uiTest1 )
        return false;

    // compare x values
    uiTest0 = *(unsigned int*)&x;
    uiTest1 = *(unsigned int*)&fXTmp;
    return uiTest0 > uiTest1;
}
//----------------------------------------------------------------------------
bool Vector2::operator>= (const Vector2& rkVector) const
{
    Real fXTmp = rkVector.x, fYTmp = rkVector.y;
    if ( FUZZ > 0.0f )
    {
        if ( Math::FAbs(x - fXTmp) <= FUZZ )
            fXTmp = x;
        if ( Math::FAbs(y - fYTmp) <= FUZZ )
            fYTmp = y;
    }

    // compare y values
    unsigned int uiTest0 = *(unsigned int*)&y;
    unsigned int uiTest1 = *(unsigned int*)&fYTmp;
    if ( uiTest0 > uiTest1 )
        return true;
    if ( uiTest0 < uiTest1 )
        return false;

    // compare x values
    uiTest0 = *(unsigned int*)&x;
    uiTest1 = *(unsigned int*)&fXTmp;
    return uiTest0 >= uiTest1;
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator+ (const Vector2& rkVector) const
{
    return Vector2(x+rkVector.x,y+rkVector.y);
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator- (const Vector2& rkVector) const
{
    return Vector2(x-rkVector.x,y-rkVector.y);
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator* (Real fScalar) const
{
    return Vector2(fScalar*x,fScalar*y);
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator- () const
{
    return Vector2(-x,-y);
}
//----------------------------------------------------------------------------
Vector2 Mgc::operator* (Real fScalar, const Vector2& rkVector)
{
    return Vector2(fScalar*rkVector.x,fScalar*rkVector.y);
}
//----------------------------------------------------------------------------
Vector2 Vector2::operator/ (Real fScalar) const
{
    Vector2 kQuot;

    if ( fScalar != 0.0f )
    {
        Real fInvScalar = 1.0f/fScalar;
        kQuot.x = fInvScalar*x;
        kQuot.y = fInvScalar*y;
        return kQuot;
    }
    else
    {
        return Vector2(Math::MAX_REAL,Math::MAX_REAL);
    }
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator+= (const Vector2& rkVector)
{
    x += rkVector.x;
    y += rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator-= (const Vector2& rkVector)
{
    x -= rkVector.x;
    y -= rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator*= (Real fScalar)
{
    x *= fScalar;
    y *= fScalar;
    return *this;
}
//----------------------------------------------------------------------------
Vector2& Vector2::operator/= (Real fScalar)
{
    if ( fScalar != 0.0f )
    {
        Real fInvScalar = 1.0f/fScalar;
        x *= fInvScalar;
        y *= fInvScalar;
    }
    else
    {
        x = Math::MAX_REAL;
        y = Math::MAX_REAL;
    }

    return *this;
}
//----------------------------------------------------------------------------
Real Vector2::Dot (const Vector2& rkVector) const
{
    return x*rkVector.x + y*rkVector.y;
}
//----------------------------------------------------------------------------
Real Vector2::Length () const
{
    return Math::Sqrt(x*x +y*y);
}
//----------------------------------------------------------------------------
Vector2 Vector2::Cross () const
{
    return Vector2(y,-x);
}
//----------------------------------------------------------------------------
Vector2 Vector2::UnitCross () const
{
    Vector2 kCross(y,-x);
    kCross.Unitize();
    return kCross;
}
//----------------------------------------------------------------------------
Real Vector2::Unitize (Real fTolerance)
{
    Real fLength = Length();

    if ( fLength > fTolerance )
    {
        Real fInvLength = 1.0f/fLength;
        x *= fInvLength;
        y *= fInvLength;
    }
    else
    {
        fLength = 0.0f;
    }

    return fLength;
}
//----------------------------------------------------------------------------
void Vector2::Orthonormalize (Vector2 akVector[/*2*/])
{
    // If the input vectors are v0 and v1, then the Gram-Schmidt
    // orthonormalization produces vectors u0 and u1 as follows,
    //
    //   u0 = v0/|v0|
    //   u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
    //
    // where |A| indicates length of vector A and A*B indicates dot
    // product of vectors A and B.

    // compute u0
    akVector[0].Unitize();

    // compute u1
    Real fDot0 = akVector[0].Dot(akVector[1]); 
    akVector[1] -= fDot0*akVector[0];
    akVector[1].Unitize();
}
//----------------------------------------------------------------------------


